﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml.Linq;

namespace VmcRemote.Common
{
    public class PluginTypeCollection<T> : IEnumerable, IEnumerable<Type>
    {
        public List<Type> Types { get; set; }
        public PluginTypeCollection()
        {
            Types = new List<Type>();
        }
        public void RegisterPlugins(string pluginFilename)
        {
            if (!File.Exists(pluginFilename)) 
                throw new ArgumentException(string.Format("Plugin file \"{0}\" does not exist", pluginFilename), "pluginFilename");
            XDocument doc = XDocument.Load(pluginFilename);
            var connectionPlugins = from plugins in doc.Descendants("plugin")
                                    where (string)plugins.Attribute("interface") == typeof(T).ToString()
                                    select new
                                    {
                                        TypeName = (string)plugins.Attribute("type"),
                                        AssemblyName = (string)plugins.Attribute("assembly")
                                    };
            foreach (var current in connectionPlugins)
            {
                string assemblyFile = Path.Combine(Path.GetDirectoryName(pluginFilename), current.AssemblyName + ".dll");
                if (File.Exists(assemblyFile))
                {
                    Assembly currentAssembly = Assembly.LoadFrom(assemblyFile);
                    Type currentType = currentAssembly.GetType(current.TypeName);
                    if (current != null)
                    {
                        foreach (Type typeInterface in currentType.GetInterfaces())
                            if (typeInterface == typeof(T)) Types.Add(currentType);
                    }
                }
            }
        }

        #region IEnumerable<IConnection> Members

        IEnumerator<Type> IEnumerable<Type>.GetEnumerator()
        {
            foreach (Type currentType in Types) yield return currentType;
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            foreach (Type currentType in Types)
            {
                string text = currentType.ToString();
                foreach (Attribute currentAttribute in currentType.GetCustomAttributes(typeof(DescriptionAttribute), true))
                {
                    DescriptionAttribute description = currentAttribute as DescriptionAttribute;
                    if (description != null)
                    {
                        text = description.Text;
                        break;
                    }
                }
                yield return text;
            }
        }

        #endregion

        public Type this[string name]
        {
            get
            {
                Type connectionType = null;
                foreach (Type currentType in Types)
                {
                    if (name == currentType.ToString())
                    {
                        connectionType = currentType;
                        break;
                    }
                    else
                    {
                        foreach (Attribute currentAttribute in currentType.GetCustomAttributes(typeof(DescriptionAttribute), true))
                        {
                            DescriptionAttribute description = currentAttribute as DescriptionAttribute;
                            if (description != null)
                            {
                                if (name == description.Text)
                                    connectionType = currentType;
                                break;
                            }
                        }
                        if (connectionType != null) break;
                    }
                }
                return connectionType;
            }
        }
    }
}
